package programming.in.scala

import scala.collection.immutable.HashSet

/**
  * Created by baiwf on 2017/5/31.
  */
object ch03_data_structure {
  def main(args: Array[String]): Unit = {
    basics()
    //listOp()
    //tupleList()
    //setAndMap()
  }

  def readLineFromFile() = {
    val lines = List("abc","1234","d","234ef")
    val longestLine = lines.reduceLeft((a,b) => //应用二元操作符到所有元素，从左到右
      if (a.length > b.length) a
      else b)
  }

  def imperativeAndFunctional(): Unit = {
    //这是完全的imperative style
    def printAgrs(args: Array[String]) = {
      var i = 0
      while (i < args.length) {
        println(args(i))
        i += 1
      }
    }
    //printArgs2/3才是more functional style。尽可能少地使用var
    //但他俩仍然有side effect,返回是Unit
    def printArgs2(args: Array[String]): Unit = {
      for (arg <- args)
        println(arg)
    }
    def printArgs3(args: Array[String]): Unit = {
      args.foreach(println)
    }

    //这是完整的functional style，有输入，有输出
    def formatArgs(args: Array[String]) = args.mkString("\n")
  }

  def setAndMap() = {
    var jetSet = Set("a","b") // 编译器推导jetSet是immutable Set[String]
    jetSet += "c" //+会返回一个Set
    println(jetSet.contains("d"))

    var movieSet = scala.collection.mutable.Set("Hitch","Poltergerist")
    movieSet += "Shrek"
    println(movieSet)

    val hashSet = HashSet("1","2") //与Set有什么区别吗？
    println(hashSet + "3")

    //没有指定value，就得写上type parameter
    val treasureMap = scala.collection.mutable.Map[Int,String]()
    treasureMap += (1 -> "island")
    treasureMap += (2 -> "ground")
    treasureMap += (3 -> "sky")
    println(treasureMap(2))
  }

  def tupleList() = {
    val pair = (1,"cs")
    println(pair._1 + "," + pair._2)
  }
  def basics(): Unit = {
    val numbers = Array("zero","one","two") //调用伴生对象apply方法

    var greetings = new Array[String](3)
    greetings.update(0,"hello")
    greetings.update(1,",")
    greetings.update(2,"world")
    for (i <- 0.to(2)) {
      print(greetings.apply(i)) //以上写法均是还原了实际操作
    }

    val oneTwo = List(1,2)
    val threeFour = List(3,4)
    val one234 = oneTwo ::: threeFour //连接会产生新的List，因为List是immutable
    println(oneTwo + " and " + threeFour + " were not mutated")
    println("Thus " + one234 + " is a new List")

    val twoThree = List(2,3)
    println(1 :: twoThree) //::表示将1放在List的首部（prepend），然后返回resulting List
    //实际上::是右操作运算符方法，凡是运算符方法如+,-,*以colon结尾，则表示将左边的当作参数
    //传递，右边的对象才是真正的调用方法的对象

    val oneTwoThree = 1 :: 2 :: 3 :: Nil //使用cons operator连接，最后一个必须用Nil,
    //因为::方法定义在List中，Nil表示空List
    println(oneTwoThree)

    //这两种不一样！
    println(List("a","b") :: List("c","d"))
    println(List("a","b") ::: List("c","d"))
  }

  def listOp(): Unit = {

    val thrill = List("Will","fill","until")
    /*
    println("thrill.count:" + thrill.count(s => s.length == 4))
    println("thrill.drop:" + thrill.drop(2))
    println("thrill.dropRight:" + thrill.dropRight(2))
    println(thrill.exists(s => s == "until"))
    println("thrill.filter:" + thrill.filter(s => s.length > 4))
    println("thrill.forall:" + thrill.forall(s => s.endsWith("l")))
    */

    //注意下面两句的打印顺序，compiler先处理右边的 !!
    println("thrill.foreach:" + thrill.foreach(s => println(s)))
    println("thrill.foreach2:" + thrill.foreach(println))
    println("thrill.head:" + thrill.head) //返回首元素
    println("thrill.tail:" + thrill.init) //返回除了最后一个的所有元素
    thrill.isEmpty
    thrill.last //返回最后一个
    println("tail:" + thrill.tail) //返回除第一个元素外的元素
    thrill.length
    println("map:" + thrill.map(s => s+"y")) //返回新的List
    println("mkstring:" + thrill.mkString(","))
    //println("remove:" + thrill.remove(s => s.length == 4))
    thrill.reverse
  }
}
